package com.oig.sys.base.service.impl;

import cn.hutool.core.bean.BeanUtil;
import com.oig.common.constants.BasicConstants;
import com.oig.common.exception.BadRequestException;
import com.oig.sys.base.constants.SysBaseConstants;
import com.oig.sys.base.constants.SysBaseEnum;
import com.oig.sys.base.dao.ITbCurrRateDao;
import com.oig.sys.base.dto.CurrRateDto;
import com.oig.sys.base.entity.TbCurrRate;
import com.oig.sys.base.service.ITbCurrRateHisService;
import com.oig.sys.base.service.ITbCurrRateService;
import com.oig.sys.base.vo.CurrRateHisVo;
import com.oig.sys.base.vo.CurrRateVo;
import com.oig.sys.base.vo.CurrencyVo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.YearMonth;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * @author wuxl
 */
@Slf4j
@Service
public class TbCurrRateServiceImpl implements ITbCurrRateService {

	private final ITbCurrRateDao tbCurrRateDao;
	private final ITbCurrRateHisService currRateHisService;

	@Autowired
	public TbCurrRateServiceImpl(ITbCurrRateDao tbCurrRateDao, ITbCurrRateHisService currRateHisService){
		 this.tbCurrRateDao = tbCurrRateDao;
		 this.currRateHisService = currRateHisService;
	}


	private CurrRateVo saveAndCov(TbCurrRate currRate, CurrRateDto currRateDto){
		BeanUtils.copyProperties(currRateDto, currRate, "id");
		currRate.setUpdateTime(new Date());
		this.tbCurrRateDao.save(currRate) ;
		CurrRateVo currRateVo = new CurrRateVo();
		BeanUtils.copyProperties(currRate, currRateVo);
		return currRateVo;
	}

	@Transactional
	@Override
	public CurrRateVo addTbCurrRate(CurrRateDto currRateDto) {
		TbCurrRate currRate = this.tbCurrRateDao.getByCurrencyAndCustomsFlag(currRateDto.getCurrency(),currRateDto.getCustomsFlag());
		if (currRate!=null){
			this.currRateHisService.addTbCurrRateHis(currRate) ;
			//this.tbCurrRateDao.delete(currRate);
		} else {
			currRate = new TbCurrRate();
		}
		return this.saveAndCov(currRate,currRateDto) ;
	}

	@Transactional
	@Override
	public CurrRateVo updateTbCurrRate(CurrRateDto currRateDto) {
		TbCurrRate currRate = this.tbCurrRateDao.getTbCurrRateById(currRateDto.getId());
		if (currRate==null){
			throw new BadRequestException("汇率不存在") ;
		}
		//currency + customs_flag 数据库建唯一约束
		return this.saveAndCov(currRate, currRateDto);
	}

	@Override
	public CurrRateVo getCurrRateByCurr(String currency, String type) {
		TbCurrRate currRate = this.tbCurrRateDao.getByCurrencyAndCustomsFlag(currency, type);
		if (currRate==null){
			return null;
		}
		CurrRateVo currRateVo = new CurrRateVo();
		BeanUtils.copyProperties(currRate, currRateVo);
		return currRateVo;
	}

	@Transactional
	@Override
	public void delTbCurrRate(Integer id) {
		this.tbCurrRateDao.deleteById(id);
	}


	@Override
	public List<CurrRateVo> findAllByType(String type) {
		List<TbCurrRate> currRateList =  this.tbCurrRateDao.findByCustomsFlag(type);
		List<CurrRateVo> voList = new ArrayList<>();
		if (currRateList!=null && !currRateList.isEmpty()){
			currRateList.forEach((currRate)->{
				CurrRateVo currRateVo = new CurrRateVo();
				BeanUtils.copyProperties(currRate, currRateVo);
				voList.add(currRateVo);
			});
		}
		return voList;
	}

	@Transactional
	@Override
	public List<CurrRateVo> addCustomsRate(List<CurrencyVo> currencyVos, List<CurrRateHisVo> currRateHisVos) {
		Map<String, CurrRateHisVo> currRateHisVoMap = currRateHisVos.stream()
				.collect(Collectors.toMap(CurrRateHisVo::getCurrency, Function.identity()));
		// 单独获取美元汇率，用于后面的对美元汇率字段计算
		BigDecimal usdRate = BigDecimal.ZERO;
		for (CurrRateHisVo currRateHisVo : currRateHisVos) {
			if (SysBaseConstants.USD_CURR.equals(currRateHisVo.getCurrency())) {
				usdRate = currRateHisVo.getBankRmbGiven();
				break;
			}
		}
		List<CurrRateVo> currRateVos = new ArrayList<>();
		Date updateTime = new Date();
		for (CurrencyVo currencyVo : currencyVos) {
			String code = currencyVo.getCode();
			CurrRateHisVo currRateHisVo = currRateHisVoMap.get(code);
			if (null == currRateHisVo) {
				log.error("未找到历史汇率数据:{}", currencyVo.getName());
				continue;
			}
			TbCurrRate currRate = tbCurrRateDao.getByCurrencyAndCustomsFlag(code, SysBaseEnum.CurrRateType.CUSTOMS.getCode());
			if (null == currRate) {
				currRate = new TbCurrRate();
			}
			BeanUtils.copyProperties(currRateHisVo, currRate, "id");
			currRate.setUpdateTime(updateTime);
			currRate.setRmbRate(currRateHisVo.getBankRmbGiven());
			currRate.setCustomsFlag(SysBaseEnum.CurrRateType.CUSTOMS.getCode());
			BigDecimal currUsdRate = usdRate.divide(currRate.getRmbRate(), BasicConstants.RATE_SCALE, RoundingMode.HALF_UP);
			currRate.setUsdRate(currUsdRate);
			TbCurrRate rate = tbCurrRateDao.save(currRate);
			CurrRateVo currRateVo = new CurrRateVo();
			BeanUtils.copyProperties(rate, currRateVo);
			currRateVos.add(currRateVo);
		}
		return currRateVos;
	}


	@Override
	public List<CurrRateVo> findAllByCurrAndYearMonth(List<String> currency, YearMonth yearMonth, String type) {
		List<TbCurrRate> allByCurrAndYearMonth = new ArrayList<>();
		if (currency.contains(BasicConstants.DEFAULT_CURR)) {
			//人民币没有yearMonth
			List<TbCurrRate> rmbRate = tbCurrRateDao.findAllByCurrencyAndCustomsFlag(BasicConstants.DEFAULT_CURR,
					SysBaseEnum.CurrRateType.CUSTOMS.getCode());
			allByCurrAndYearMonth.addAll(rmbRate);
		}
		allByCurrAndYearMonth.addAll(this.tbCurrRateDao.findAllByCurrAndYearMonth(currency,
				yearMonth.toString(), type));

		return BeanUtil.copyToList(allByCurrAndYearMonth, CurrRateVo.class);
	}

	@Override
	public List<CurrRateVo> listAll() {
		List<TbCurrRate> all = tbCurrRateDao.findAll();
		return BeanUtil.copyToList(all, CurrRateVo.class);
	}

}
